﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;
using System.Reflection;
using System.Runtime.InteropServices;


namespace Sinacor.OMM.FileTail
{

    public partial class TraceTail : Form
    {
        [DllImport("user32")]
        public static extern int SendMessage(int hwnd, int msg, int wparam, int lparam);

        // Split 2 Horizontal
        public const int WM_SPLIT2H1 = 0x400;        // 0x400 //Janela1
        public const int WM_SPLIT2H2 = 0x401;        // 0x401 //Janela2

        // Split 2 Vertical
        public const int WM_SPLIT2V1 = 0x402;        // 0x402 //Janela1
        public const int WM_SPLIT2V2 = 0x403;        // 0x403 //Janela2

        // Split 3 Horizontal
        public const int WM_SPLIT3H1 = 0x404;        // 0x404 //Janela1
        public const int WM_SPLIT3H2 = 0x405;        // 0x405 //Janela2
        public const int WM_SPLIT3H3 = 0x406;        // 0x406 //Janela3

        // Split 3 Vertical
        public const int WM_SPLIT3V1 = 0x407;        // 0x407 //Janela1
        public const int WM_SPLIT3V2 = 0x408;        // 0x408 //Janela2
        public const int WM_SPLIT3V3 = 0x409;        // 0x409 //Janela3

        // Split 4
        public const int WM_SPLIT4_1 = 0x410;        // 0x410 //Janela1
        public const int WM_SPLIT4_2 = 0x411;        // 0x411 //Janela2
        public const int WM_SPLIT4_3 = 0x412;        // 0x412 //Janela3
        public const int WM_SPLIT4_4 = 0x413;        // 0x413 //Janela4

        // Split 6
        public const int WM_SPLIT6_1 = 0x414;        // 0x414 //Janela1
        public const int WM_SPLIT6_2 = 0x415;        // 0x415 //Janela2
        public const int WM_SPLIT6_3 = 0x416;        // 0x416 //Janela3
        public const int WM_SPLIT6_4 = 0x417;        // 0x417 //Janela4
        public const int WM_SPLIT6_5 = 0x418;        // 0x418 //Janela5
        public const int WM_SPLIT6_6 = 0x419;        // 0x419 //Janela6

        // Close Window
        public const int WM_CLOSE = 0x0010;          // Fechar Janela

        private const string CHR1013 = "\r\n";
        private const int TIME_TO_WRITE_BUFFERED_DATA_WHEN_FOLLOWING = 250;
        private const int TIME_TO_WRITE_BUFFERED_DATA_WHEN_SCROOLING = 1;

        private static int _numberOfFilesLastUsed = 0;
        private OpenFileDialog _ofd;
        private DialogResult _dr;
        private FileVirtualization _fileVirtualization;
        private UserExperienceHelper _userExperienceHelper;

        private string _guidOne = string.Empty;
        private string _guidTen = string.Empty;

        private bool _keepRunning;
        private bool _contentChanged;
        private bool _fileSizeChanged;
        private bool _offSetChanged;
        private bool _fileNameChanged;

        private int _visibleLines = 0;
        private int _timeToWriteBufferedData = TIME_TO_WRITE_BUFFERED_DATA_WHEN_SCROOLING;

        public TraceTail(string fileNameArgument)
        {
            InitializeComponent();

            _ofd = new OpenFileDialog();
            _userExperienceHelper = new UserExperienceHelper(Application.LocalUserAppDataPath);

            _fileVirtualization = new FileVirtualization();
            _fileVirtualization.OnFileSizeChanged += new FileVirtualization.FileSizeChangedHandler(_fileVirtualization_OnFileSizeChanged);
            _fileVirtualization.OnVirtualizedContentChanged += new FileVirtualization.VirtualizedContentChangedHandler(_fileVirtualization_OnVirtualizedContentChanged);
            _fileVirtualization.OnNextLineStartChanged += new FileVirtualization.NextLineStartIndexChangedHandler(_fileVirtualization_OnNextLineStartChanged);
            _fileVirtualization.OnFileNameChanged += new FileVirtualization.FileNameChangedHandler(_fileVirtualization_OnFileNameChanged);
            _fileVirtualization.OnEndOfFileReached += new FileVirtualization.EndOfFileReachedHandler(_fileVirtualization_OnEndOfFileReached);

            StartBufferdContentWriter();

            if (fileNameArgument != string.Empty)
            {
                OpenFile(fileNameArgument);
            }
            else
            {
                string lastUsedFileName = _userExperienceHelper.LoadLastUsedFile();

                if (!string.IsNullOrEmpty(lastUsedFileName))
                {
                    OpenFile(lastUsedFileName);
                }
                else
                {
                    LoadLastUsedFilesMenu();
                }
            }

        }


        #region Buffered Screen Writer

        private void StartBufferdContentWriter()
        {
            if (!_keepRunning)
            {
                Thread thr = new Thread(new ThreadStart(BufferedScreenWriter));
                thr.Start();
            }
        }

        private void StopBufferedContentWriter()
        {
            _keepRunning = false;
        }

        private void BufferedScreenWriter()
        {

            _keepRunning = true;

            while (_keepRunning)
            {
                if (_contentChanged)
                {
                    _contentChanged = false;
                    if (_fileVirtualization.VirtualizedContent.EndsWith(CHR1013))
                        SetText(txtContent, _fileVirtualization.VirtualizedContent.Substring(0, _fileVirtualization.VirtualizedContent.Length - CHR1013.Length));
                    else
                        SetText(txtContent, _fileVirtualization.VirtualizedContent);
                }

                if (_fileSizeChanged)
                {
                    _fileSizeChanged = false;
                    SetToolStripStatusLabel(toolStripStatusFileSize, "(" + _userExperienceHelper.GetSizeUnits(_fileVirtualization.FileLength) + ")");
                }

                if (_offSetChanged)
                {
                    _offSetChanged = false;
                    SetToolStripStatusLabel(toolStripStatusNextLineStartIndex, "[" + _fileVirtualization.NextLineStartIndex.ToString() + "]");
                }

                if (_fileNameChanged)
                {
                    _fileNameChanged = false;
                    SetToolStripStatusLabel(toolStripStatusFileName, _fileVirtualization.FileName);
                }

                Thread.Sleep(_timeToWriteBufferedData);
            }
        }

        #endregion


        #region FileVirtualization events

        private void _fileVirtualization_OnVirtualizedContentChanged(string content)
        {
            _contentChanged = true;
        }

        private void _fileVirtualization_OnFileSizeChanged(int fileSize)
        {
            _fileSizeChanged = true;
        }

        void _fileVirtualization_OnNextLineStartChanged(int nextLineStartIndex)
        {
            _offSetChanged = true;
        }

        void _fileVirtualization_OnFileNameChanged(string filename)
        {
            _fileNameChanged = true;
        }

        void _fileVirtualization_OnEndOfFileReached(int filesize)
        {
            SetVScrollBarMaximum(vScrBar, _fileVirtualization.FileLength);
            SetVScrollBarValue(vScrBar, filesize);
        }

        #endregion


        #region Menu Events

        private void abrirToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFile(string.Empty);
        }

        private void sairToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
            this.Dispose();
        }

        void TraceTail_Click(object sender, EventArgs e)
        {
            string safeFileName;
            string fileNameToOpen = string.Empty;
            Dictionary<string, string> lastUsedFilesDict;


            safeFileName = ((ToolStripMenuItem)sender).Text;
            lastUsedFilesDict = _userExperienceHelper.GetLastUsedFiles();


            foreach (string filename in lastUsedFilesDict.Keys)
            {
                if (safeFileName == lastUsedFilesDict[filename])
                {
                    fileNameToOpen = filename;
                    break;
                }
            }

            OpenFile(fileNameToOpen);
        }

        private void editToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (_fileVirtualization.FileLength < (1024 * 1024) * 15) //Até 15 Mega
            {
                Process.Start("Notepad.exe", _fileVirtualization.FileName);
            }
            else
            {
                MessageBox.Show("File is too big for Notepad");
            }
        }

        private void fecharToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CloseFile();
            //Grava como último arquivo usado para carregar na próxima vez...
            _userExperienceHelper.SaveLastUsedFile(string.Empty);
        }


        private void tsmiAllWinSplit2Horiz_Click(object sender, EventArgs e)
        {
            PostRemoteCommandWindowMessage(WM_SPLIT2H1, 2);
        }

        private void tsmiAllWinSplit2Vert_Click(object sender, EventArgs e)
        {
            PostRemoteCommandWindowMessage(WM_SPLIT2V1, 2);
        }

        private void tsmiAllWinSplit3Horiz_Click(object sender, EventArgs e)
        {
            PostRemoteCommandWindowMessage(WM_SPLIT3H1, 3);
        }

        private void tsmiAllWinSplit3Vert_Click(object sender, EventArgs e)
        {
            PostRemoteCommandWindowMessage(WM_SPLIT3V1, 3);
        }

        private void tsmiAllWinSplit2x2_Click(object sender, EventArgs e)
        {
            PostRemoteCommandWindowMessage(WM_SPLIT4_1, 4);
        }

        private void tsmiAllWinSplit3x2_Click(object sender, EventArgs e)
        {
            PostRemoteCommandWindowMessage(WM_SPLIT6_1, 6);
        }

        private void tsmiAllWinClose_Click(object sender, EventArgs e)
        {
            PostRemoteCommandWindowMessage(WM_CLOSE, 1);
        }

        private void tsmiAllWinCloseButThis_Click(object sender, EventArgs e)
        {
            PostRemoteCommandWindowMessage(WM_CLOSE, 1, true);
        }

        private void tsmiThisWinSplit2Horiz_Click(object sender, EventArgs e)
        {
            pnlWindowPos2h.Visible = true;
        }

        private void tsmiThisWinSplit2Vert_Click(object sender, EventArgs e)
        {
            pnlWindowPos2v.Visible = true;
        }

        private void tsmiThisWinSplit3Horiz_Click(object sender, EventArgs e)
        {
            pnlWindowPos3h.Visible = true;
        }

        private void tsmiThisWinSplit3Vert_Click(object sender, EventArgs e)
        {
            pnlWindowPos3v.Visible = true;
        }

        private void tsmiThisWinSplit2x2_Click(object sender, EventArgs e)
        {
            pnlWindowPos4.Visible = true;
        }

        private void tsmiThisWinSplit3x2_Click(object sender, EventArgs e)
        {
            pnlWindowPos6.Visible = true;
        }



        #endregion


        #region Open/Close File user iteration

        private delegate void dOpenFile(string fileNameArgument);
        private void OpenFile(string fileNameArgument)
        {
            if (this.InvokeRequired)
            {
                try
                {
                    dOpenFile d = new dOpenFile(OpenFile);
                    this.Invoke(d, new object[] { fileNameArgument });
                }
                catch (Exception) { }
            }
            else
            {

                _ofd.CheckFileExists = true;
                _ofd.RestoreDirectory = true;
                _ofd.Title = "TraceTail - File Open";
                _ofd.ValidateNames = true;

                if (fileNameArgument == string.Empty)
                {
                    //Se o arquivo não veio como parâmetro, mostra o Dialogbox
                    _dr = _ofd.ShowDialog();
                }
                else
                {
                    //Se o arquivo não veio como parâmetro apenas atribui para validação
                    _ofd.FileName = fileNameArgument;
                }

                //Se veio um aquivo como parâmetro do EXE ou via Dialog
                if (!string.IsNullOrEmpty(_ofd.FileName))
                {
                    //Para de seguir o fim de arquivo
                    chkFollowing.Checked = false;

                    //Fecha algum arquivo se já estiver aberto e abre o novo
                    _fileVirtualization.CloseFile();
                    _fileVirtualization.FileName = _ofd.FileName;

                    if (_fileVirtualization.OpenFile())
                    {

                        //Grava como último arquivo usado para carregar na próxima vez...
                        _userExperienceHelper.SaveLastUsedFile(_fileVirtualization.FileName);

                        //Define os novos valores de scroll bar, conforme o novo arquivo...
                        vScrBar.Minimum = 0;
                        vScrBar.Maximum = _fileVirtualization.FileLength;
                        vScrBar.Value = 0; //Força disparar a mudanã de valor

                        hScrBar.Maximum = 350;
                        hScrBar.Value = 0;

                        //Reseta os valores do GuideLine os novos valores de scroll bar, conforme o novo arquivo                
                        lblGuideOne.Text = _guidOne;
                        lblGuideTen.Text = _guidTen;

                        //Define o título da janela
                        this.Text = _ofd.SafeFileName + " - Trace Tail";

                        //Adiciona á lista de últimos arquivos usados
                        _userExperienceHelper.AddLastUsedFile(_ofd.FileName, _ofd.SafeFileName);

                        //Habilita o menu Fechar arquivo
                        fecharToolStripMenuItem.Enabled = true;

                        //Começa a seguir o final do novo arquivo aberto.
                        //chkFollowing.Checked = true;
                        VisibleLinesCalc();

                        _fileVirtualization.VirtualizeFirstLines(hScrBar.Value);
                        vScrBar.Value = _fileVirtualization.NextLineStartIndex;
                        vScrBar.Minimum = _fileVirtualization.NextLineStartIndex;

                        chkFollowing.Checked = true;
                    }

                    //Recarrega a lista de últimos arquivos usado
                    LoadLastUsedFilesMenu();
                }
            }
        }

        private delegate void dCloseFile();
        private void CloseFile()
        {
            if (this.InvokeRequired)
            {
                try
                {
                    dCloseFile d = new dCloseFile(CloseFile);
                    this.Invoke(d);
                }
                catch (Exception) { }
            }
            else
            {

                _fileVirtualization.CloseFile();

                fecharToolStripMenuItem.Enabled = false;
                chkFollowing.Checked = false;

                lblGuideOne.Text = _guidOne;
                lblGuideTen.Text = _guidTen;

                vScrBar.Minimum = 0;
                vScrBar.Maximum = 350;
                vScrBar.Value = 0;
                hScrBar.Maximum = 350;
                hScrBar.Value = 0;

                this.Text = "Trace Tail 1.0";
            }
        }

        private void LoadLastUsedFilesMenu()
        {
            Dictionary<string, string> lastUsedFilesList = _userExperienceHelper.GetLastUsedFiles();

            toolStripDropDownItensLastFiles.DropDownItems.Clear();

            for (int idx = 0; idx < toolStripDropDownItensLastFiles.DropDownItems.Count; idx++)
            {
                toolStripDropDownItensLastFiles.DropDownItems[idx].Dispose();
            }

            foreach (string safeFileName in lastUsedFilesList.Values)
            {
                ToolStripMenuItem asToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
                asToolStripMenuItem.Name = safeFileName + _numberOfFilesLastUsed++;
                asToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
                asToolStripMenuItem.Text = safeFileName;
                asToolStripMenuItem.Click += new System.EventHandler(TraceTail_Click);
                toolStripDropDownItensLastFiles.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { asToolStripMenuItem });
            }
        }
        #endregion


        #region Screen Objects Events

        private void vScrBar_Scroll(object sender, ScrollEventArgs e)
        {
            if (_fileVirtualization.FileOpened)
            {
                int diffValueChanged = e.NewValue - e.OldValue;

                // Se não houve mudança e valor não faz nada
                if (diffValueChanged == 0)
                {
                    return;
                }

                //Se a barra atingir o limite máximo
                if (vScrBar.Value >= vScrBar.Maximum - 9)
                {
                    chkFollowing.Checked = true;
                    return; // Vai começar a seguir o fim de arquivo e a ScrollBar não deve ser considerada
                }
                else // Para de seguir o fim de arquivo e considera a ScrollBar
                {
                    chkFollowing.Checked = false;
                }

                //Se chegar no topo da ScrollBar
                if (e.NewValue == vScrBar.Minimum)
                {
                    int valor = _fileVirtualization.VirtualizeFirstLines(hScrBar.Value);
                    SetVScrollBarMaximum(vScrBar, _fileVirtualization.FileLength);
                    SetVScrollBarValue(vScrBar, valor);
                    return;
                }

                //Se tiver pulando linha a linha para baixo
                if (diffValueChanged == 1)
                {
                    int valor = _fileVirtualization.VirtualizeNextLine(hScrBar.Value);
                    SetVScrollBarMaximum(vScrBar, _fileVirtualization.FileLength);
                    SetVScrollBarValue(vScrBar, valor);
                }
                else if (diffValueChanged == -1)            //Se tiver pulando linha a linha para Cima
                {
                    int valor = _fileVirtualization.VirtualizePreviousLine(hScrBar.Value);
                    SetVScrollBarMaximum(vScrBar, _fileVirtualization.FileLength);
                    SetVScrollBarValue(vScrBar, valor);
                }
                else if (diffValueChanged != 0) // Se tiver scrolando com grandes mudanças
                {
                    if (e.OldValue < e.NewValue)
                    {
                        //int valor = _fileVirtualization.VirtualizeNextLine(hScrBar.Value);
                        //SetVScrollBarMaximum(vScrBar, _fileVirtualization.FileLength);
                        //SetVScrollBarValue(vScrBar, valor);
                        int valor = _fileVirtualization.VirtualizeAfterPostion(vScrBar.Value, hScrBar.Value);
                        SetVScrollBarMaximum(vScrBar, _fileVirtualization.FileLength);
                        SetVScrollBarValue(vScrBar, valor);
                    }
                    else
                    {
                        //int valor = _fileVirtualization.VirtualizePreviousLine(hScrBar.Value);
                        //SetVScrollBarMaximum(vScrBar, _fileVirtualization.FileLength);
                        //SetVScrollBarValue(vScrBar, valor);
                        int valor = _fileVirtualization.VirtualizeBeforePostion(vScrBar.Value, hScrBar.Value);
                        SetVScrollBarMaximum(vScrBar, _fileVirtualization.FileLength);
                        SetVScrollBarValue(vScrBar, valor);
                    }
                }
            }
        }

        private void hScrBar_Scroll(object sender, ScrollEventArgs e)
        {
            if (_fileVirtualization.FileOpened)
            {
                _fileVirtualization.SetHorizontalPosition(hScrBar.Value);
                _fileVirtualization.VirtualizeHorizontal(hScrBar.Value);

                if (hScrBar.Value == hScrBar.Maximum - 9)
                    hScrBar.Maximum = hScrBar.Maximum + (hScrBar.Maximum * 25 / 100);

                lblGuideOne.Text = _guidOne.Substring(hScrBar.Value);
                lblGuideTen.Text = _guidTen.Substring(hScrBar.Value);
            }
        }

        private void chkFollowing_CheckedChanged(object sender, EventArgs e)
        {
            if (_fileVirtualization.FileOpened)
            {
                if (chkFollowing.Checked)
                {
                    _fileVirtualization.StartTailFollower();
                    _timeToWriteBufferedData = TIME_TO_WRITE_BUFFERED_DATA_WHEN_FOLLOWING;
                }
                else
                {
                    _fileVirtualization.StopTailFollower();
                    _timeToWriteBufferedData = TIME_TO_WRITE_BUFFERED_DATA_WHEN_SCROOLING;
                }
            }
        }

        private void txtContent_SizeChanged(object sender, EventArgs e)
        {
            VisibleLinesCalc();
            if (!chkFollowing.Checked)
            {
                _fileVirtualization.VirtualizeHorizontal(hScrBar.Value);
            }
            else
            {
                _fileVirtualization.RefreshControl = true;
            }
        }

        private void txtContent_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {
            if (_fileVirtualization.FileOpened)
            {
                if (e.KeyCode == Keys.Up)
                {
                    chkFollowing.Checked = false;
                    int valor = _fileVirtualization.VirtualizePreviousLine(hScrBar.Value);
                    SetVScrollBarMaximum(vScrBar, _fileVirtualization.FileLength);
                    SetVScrollBarValue(vScrBar, valor);
                }

                if (e.KeyCode == Keys.Down)
                {
                    chkFollowing.Checked = false;
                    int valor = _fileVirtualization.VirtualizeNextLine(hScrBar.Value);
                    SetVScrollBarMaximum(vScrBar, _fileVirtualization.FileLength);
                    SetVScrollBarValue(vScrBar, valor);
                }

                if (e.KeyCode == Keys.Home)
                {
                    chkFollowing.Checked = false;
                    int valor = _fileVirtualization.VirtualizeFirstLines(hScrBar.Value);
                    SetVScrollBarMaximum(vScrBar, _fileVirtualization.FileLength);
                    SetVScrollBarValue(vScrBar, valor);
                }

                if (e.KeyCode == Keys.End)
                {
                    chkFollowing.Checked = false;
                    int valor = _fileVirtualization.VirtualizeLastLines(hScrBar.Value);
                    SetVScrollBarMaximum(vScrBar, _fileVirtualization.FileLength);
                    SetVScrollBarValue(vScrBar, valor);
                }

                if (e.KeyCode == Keys.Left)
                {
                    if (hScrBar.Value > hScrBar.Minimum)
                    {
                        hScrBar.Value = hScrBar.Value - 1;
                        hScrBar.Update();

                        _fileVirtualization.SetHorizontalPosition(hScrBar.Value);
                        _fileVirtualization.VirtualizeHorizontal(hScrBar.Value);

                        lblGuideOne.Text = _guidOne.Substring(hScrBar.Value);
                        lblGuideTen.Text = _guidTen.Substring(hScrBar.Value);
                    }

                }

                if (e.KeyCode == Keys.Right)
                {
                    if (hScrBar.Value == hScrBar.Maximum - 9)
                        hScrBar.Maximum = hScrBar.Maximum + (hScrBar.Maximum * 25 / 100);

                    hScrBar.Value = hScrBar.Value + 1;
                    hScrBar.Update();

                    _fileVirtualization.SetHorizontalPosition(hScrBar.Value);
                    _fileVirtualization.VirtualizeHorizontal(hScrBar.Value);

                    lblGuideOne.Text = _guidOne.Substring(hScrBar.Value);
                    lblGuideTen.Text = _guidTen.Substring(hScrBar.Value);
                }

                if (e.KeyCode == Keys.PageDown)
                {
                    chkFollowing.Checked = false;
                    for (int idx = 0; idx < _visibleLines; idx++)
                    {
                        int valor = _fileVirtualization.VirtualizeNextLine(hScrBar.Value);
                        SetVScrollBarMaximum(vScrBar, _fileVirtualization.FileLength);
                        SetVScrollBarValue(vScrBar, valor);
                    }
                }

                if (e.KeyCode == Keys.PageUp)
                {
                    chkFollowing.Checked = false;
                    for (int idx = 0; idx < _visibleLines; idx++)
                    {
                        int valor = _fileVirtualization.VirtualizePreviousLine(hScrBar.Value);
                        SetVScrollBarMaximum(vScrBar, _fileVirtualization.FileLength);
                        SetVScrollBarValue(vScrBar, valor);
                    }
                }
            }
        }

        #endregion


        #region Eventos do Form
        private void TraceTail_FormClosing(object sender, FormClosingEventArgs e)
        {

            StopBufferedContentWriter();
            _keepRunning = false;
            CloseFile();
            _fileVirtualization.Dispose();
            Application.Exit();
        }

        private void TraceTail_Load(object sender, EventArgs e)
        {

            for (int idx = 0; idx < 10000; idx = idx + 10)
            {
                if (idx == 0)
                {
                    _guidTen += idx.ToString();
                    StringBuilder sb = new StringBuilder();
                    _guidTen += sb.Append(' ', 9 - idx.ToString().Length).ToString();

                    _guidOne += "|";
                    StringBuilder sb2 = new StringBuilder();
                    _guidOne += sb2.Append('¬', 8).ToString();
                }
                else
                {
                    _guidTen += idx.ToString();
                    StringBuilder sb3 = new StringBuilder();
                    _guidTen += sb3.Append(' ', 10 - idx.ToString().Length).ToString();


                    _guidOne += "|";
                    StringBuilder sb4 = new StringBuilder();
                    _guidOne += sb4.Append('¬', 9).ToString();
                }
            }

            lblGuideOne.Text = _guidOne;
            lblGuideTen.Text = _guidTen;

            VisibleLinesCalc();
        }

        #endregion


        #region Cross Thread Operations

        private void SetVScrollBarMaximum(VScrollBar vScrollBar, int value)
        {
            SetVScrollBarMaximum(vScrollBar, value, 0);
        }

        private delegate void dSetVScrollBarMaximum(VScrollBar vScrollBar, int valor, int limit);
        private void SetVScrollBarMaximum(VScrollBar vScrollBar, int valor, int limit)
        {

            if (limit == 0)
            {
                try
                {
                    dSetVScrollBarMaximum d = new dSetVScrollBarMaximum(SetVScrollBarMaximum);
                    this.Invoke(d, new object[] { vScrollBar, valor, 1 });
                }
                catch (Exception) { }
            }
            else
            {
                vScrollBar.Maximum = valor;
                //vScrollBar.Update();
                toolStripStatusLabelVscrBarMax.Text = "[" + vScrollBar.Maximum.ToString() + "]";
            }
        }

        private void SetVScrollBarValue(VScrollBar vScrollBar, int value)
        {
            SetVScrollBarValue(vScrollBar, value, 0);
        }

        private delegate void dSetVScrollBarValue(VScrollBar vScrollBar, int valor, int limit);
        private void SetVScrollBarValue(VScrollBar vScrollBar, int valor, int limit)
        {

            if (limit == 0)
            {
                try
                {
                    dSetVScrollBarValue d = new dSetVScrollBarValue(SetVScrollBarValue);
                    this.Invoke(d, new object[] { vScrollBar, valor, 1 });
                }
                catch (Exception) { }
            }
            else
            {
                if (valor > vScrollBar.Maximum)
                    vScrollBar.Maximum = valor;

                vScrollBar.Value = valor;
                vScrollBar.Update();

                toolStripStatusScrollBarValue.Text = "[" + vScrBar.Value.ToString() + "]";
            }
        }

        delegate void dSetText(TextBox textBox, string text);
        private void SetText(TextBox textBox, string text)
        {
            if (this.InvokeRequired)
            {
                try
                {
                    dSetText d = new dSetText(SetText);
                    this.Invoke(d, new object[] { textBox, text });
                }
                catch (Exception) { }
            }
            else
            {
                textBox.Text = text;
                //if (vScrBar.Value == 0)
                //    txtContent.SelectionStart = 0;
                //else
                //    txtContent.SelectionStart = txtContent.Text.Length;
                textBox.SelectionStart = 0;
                textBox.ScrollToCaret();

            }
        }

        delegate void dSetToolStripStatusLabel(ToolStripStatusLabel toolStripStatusLabel, string text);
        private void SetToolStripStatusLabel(ToolStripStatusLabel toolStripStatusLabel, string text)
        {
            if (this.InvokeRequired)
            {
                try
                {
                    dSetToolStripStatusLabel d = new dSetToolStripStatusLabel(SetToolStripStatusLabel);
                    this.Invoke(d, new object[] { toolStripStatusLabel, text });
                }
                catch (Exception) { }
            }
            else
            {
                toolStripStatusLabel.Text = text;
            }
        }

        #endregion


        #region Window Position


        #region 6 parts
        private void btnPos6_1_Click(object sender, EventArgs e)
        {
            int posYini = 0;
            int posXini = 0;
            int windowHeight = (Screen.PrimaryScreen.WorkingArea.Height / 3) - 1;
            int windowWidth = (Screen.PrimaryScreen.WorkingArea.Width / 2) - 1;
            SetWindow(posXini, posYini, windowWidth, windowHeight);
            pnlWindowPos6.Visible = false;
        }

        private void btnPos6_2_Click(object sender, EventArgs e)
        {
            int posYini = 0;
            int posXini = (Screen.PrimaryScreen.WorkingArea.Width / 2) + 1;
            int windowHeight = (Screen.PrimaryScreen.WorkingArea.Height / 3) - 1;
            int windowWidth = Screen.PrimaryScreen.WorkingArea.Width - (Screen.PrimaryScreen.WorkingArea.Width / 2);
            SetWindow(posXini, posYini, windowWidth, windowHeight);
            pnlWindowPos6.Visible = false;
        }


        private void btnPos6_3_Click(object sender, EventArgs e)
        {
            int posYini = (Screen.PrimaryScreen.WorkingArea.Height / 3) + 1;
            int posXini = 0;
            int windowHeight = (Screen.PrimaryScreen.WorkingArea.Height / 3) - 1;
            int windowWidth = (Screen.PrimaryScreen.WorkingArea.Width / 2) - 1;
            SetWindow(posXini, posYini, windowWidth, windowHeight);
            pnlWindowPos6.Visible = false;
        }


        private void btnPos6_4_Click(object sender, EventArgs e)
        {
            int posYini = (Screen.PrimaryScreen.WorkingArea.Height / 3) + 1;
            int posXini = (Screen.PrimaryScreen.WorkingArea.Width / 2) + 1;
            int windowHeight = (Screen.PrimaryScreen.WorkingArea.Height / 3) - 1;
            int windowWidth = (Screen.PrimaryScreen.WorkingArea.Width / 2) - 1;
            SetWindow(posXini, posYini, windowWidth, windowHeight);
            pnlWindowPos6.Visible = false;
        }

        private void btnPos6_5_Click(object sender, EventArgs e)
        {
            int posYini = ((Screen.PrimaryScreen.WorkingArea.Height / 3) * 2) + 1;
            int posXini = 0;
            int windowHeight = (Screen.PrimaryScreen.WorkingArea.Height / 3) - 1;
            int windowWidth = (Screen.PrimaryScreen.WorkingArea.Width / 2) - 1;
            SetWindow(posXini, posYini, windowWidth, windowHeight);
            pnlWindowPos6.Visible = false;
        }


        private void btnPos6_6_Click(object sender, EventArgs e)
        {
            int posYini = ((Screen.PrimaryScreen.WorkingArea.Height / 3) * 2) + 1;
            int posXini = (Screen.PrimaryScreen.WorkingArea.Width / 2) + 1;
            int windowHeight = (Screen.PrimaryScreen.WorkingArea.Height / 3) - 1;
            int windowWidth = (Screen.PrimaryScreen.WorkingArea.Width / 2) - 1;
            SetWindow(posXini, posYini, windowWidth, windowHeight);
            pnlWindowPos6.Visible = false;
        }


        private void btnPos6_Cancel_Click(object sender, EventArgs e)
        {
            pnlWindowPos6.Visible = false;
        }

        #endregion

        #region 4 parts

        private void btnPos4_1_Click(object sender, EventArgs e)
        {
            int posYini = 0;
            int posXini = 0;
            int windowHeight = (Screen.PrimaryScreen.WorkingArea.Height / 2) - 1;
            int windowWidth = (Screen.PrimaryScreen.WorkingArea.Width / 2) - 1;
            SetWindow(posXini, posYini, windowWidth, windowHeight);
            pnlWindowPos4.Visible = false;
        }

        private void btnPos4_2_Click(object sender, EventArgs e)
        {
            int posYini = 0;
            int posXini = (Screen.PrimaryScreen.WorkingArea.Width / 2) + 1;
            int windowHeight = (Screen.PrimaryScreen.WorkingArea.Height / 2) - 1;
            int windowWidth = Screen.PrimaryScreen.WorkingArea.Width - (Screen.PrimaryScreen.WorkingArea.Width / 2);
            SetWindow(posXini, posYini, windowWidth, windowHeight);
            pnlWindowPos4.Visible = false;
        }

        private void btnPos4_3_Click(object sender, EventArgs e)
        {
            int posYini = (Screen.PrimaryScreen.WorkingArea.Height / 2) + 1;
            int posXini = 0;
            int windowHeight = (Screen.PrimaryScreen.WorkingArea.Height / 2) - 1;
            int windowWidth = (Screen.PrimaryScreen.WorkingArea.Width / 2) - 1;
            SetWindow(posXini, posYini, windowWidth, windowHeight);
            pnlWindowPos4.Visible = false;
        }

        private void btnPos4_4_Click(object sender, EventArgs e)
        {
            int posYini = (Screen.PrimaryScreen.WorkingArea.Height / 2) + 1;
            int posXini = (Screen.PrimaryScreen.WorkingArea.Width / 2) + 1;
            int windowHeight = (Screen.PrimaryScreen.WorkingArea.Height / 2) - 1;
            int windowWidth = (Screen.PrimaryScreen.WorkingArea.Width / 2) - 1;
            SetWindow(posXini, posYini, windowWidth, windowHeight);
            pnlWindowPos4.Visible = false;
        }

        private void btnPos4_Cancel_Click(object sender, EventArgs e)
        {
            pnlWindowPos4.Visible = false;
        }

        #endregion

        #region 3 parts horizontal

        private void btnPos3h_1_Click(object sender, EventArgs e)
        {
            int posYini = 0;
            int posXini = 0;
            int windowHeight = (Screen.PrimaryScreen.WorkingArea.Height / 3) - 1;
            int windowWidth = Screen.PrimaryScreen.WorkingArea.Width;
            SetWindow(posXini, posYini, windowWidth, windowHeight);
            pnlWindowPos3h.Visible = false;
        }

        private void btnPos3h_2_Click(object sender, EventArgs e)
        {
            int posYini = (Screen.PrimaryScreen.WorkingArea.Height / 3) + 1;
            int posXini = 0;
            int windowHeight = (Screen.PrimaryScreen.WorkingArea.Height / 3) - 1;
            int windowWidth = Screen.PrimaryScreen.WorkingArea.Width;
            SetWindow(posXini, posYini, windowWidth, windowHeight);
            pnlWindowPos3h.Visible = false;
        }

        private void btnPos3h_3_Click(object sender, EventArgs e)
        {
            int posYini = ((Screen.PrimaryScreen.WorkingArea.Height / 3) * 2) + 1;
            int posXini = 0;
            int windowHeight = (Screen.PrimaryScreen.WorkingArea.Height / 3) - 1;
            int windowWidth = Screen.PrimaryScreen.WorkingArea.Width;
            SetWindow(posXini, posYini, windowWidth, windowHeight);
            pnlWindowPos3h.Visible = false;
        }

        private void btnPos3h_Cancel_Click(object sender, EventArgs e)
        {
            pnlWindowPos3h.Visible = false;
        }

        #endregion

        #region 3 parts vertical
        private void btnPos3v_1_Click(object sender, EventArgs e)
        {
            int posYini = 0;
            int posXini = 0;
            int windowHeight = Screen.PrimaryScreen.WorkingArea.Height;
            int windowWidth = (Screen.PrimaryScreen.WorkingArea.Width / 3) - 1;
            SetWindow(posXini, posYini, windowWidth, windowHeight);
            pnlWindowPos3v.Visible = false;
        }

        private void btnPos3v_2_Click(object sender, EventArgs e)
        {
            int posYini = 0;
            int posXini = (Screen.PrimaryScreen.WorkingArea.Width / 3) + 1;
            int windowHeight = Screen.PrimaryScreen.WorkingArea.Height;
            int windowWidth = (Screen.PrimaryScreen.WorkingArea.Width / 3) - 1;
            SetWindow(posXini, posYini, windowWidth, windowHeight);
            pnlWindowPos3v.Visible = false;
        }

        private void btnPos3v_3_Click(object sender, EventArgs e)
        {
            int posYini = 0;
            int posXini = ((Screen.PrimaryScreen.WorkingArea.Width / 3) * 2) + 1;
            int windowHeight = Screen.PrimaryScreen.WorkingArea.Height;
            int windowWidth = (Screen.PrimaryScreen.WorkingArea.Width / 3) - 1;
            SetWindow(posXini, posYini, windowWidth, windowHeight);
            pnlWindowPos3v.Visible = false;
        }

        private void btnPos3v_Cancel_Click(object sender, EventArgs e)
        {
            pnlWindowPos3v.Visible = false;
        }

        #endregion

        #region 2 parts horizontal
        private void btnPos2h_1_Click(object sender, EventArgs e)
        {
            int posYini = 0;
            int posXini = 0;
            int windowHeight = (Screen.PrimaryScreen.WorkingArea.Height / 2) - 1;
            int windowWidth = Screen.PrimaryScreen.WorkingArea.Width;
            SetWindow(posXini, posYini, windowWidth, windowHeight);
            pnlWindowPos2h.Visible = false;
        }

        private void btnPos2h_2_Click(object sender, EventArgs e)
        {
            int posYini = (Screen.PrimaryScreen.WorkingArea.Height / 2) + 1;
            int posXini = 0;
            int windowHeight = (Screen.PrimaryScreen.WorkingArea.Height / 2) - 1;
            int windowWidth = Screen.PrimaryScreen.WorkingArea.Width;
            SetWindow(posXini, posYini, windowWidth, windowHeight);
            pnlWindowPos2h.Visible = false;
        }
        private void btnPos2h_Cancel_Click(object sender, EventArgs e)
        {
            pnlWindowPos2h.Visible = false;
        }

        #endregion

        #region 2 parts vertical
        private void btnPos2v_1_Click(object sender, EventArgs e)
        {
            int posYini = 0;
            int posXini = 0;
            int windowHeight = Screen.PrimaryScreen.WorkingArea.Height;
            int windowWidth = (Screen.PrimaryScreen.WorkingArea.Width / 2) - 1;
            SetWindow(posXini, posYini, windowWidth, windowHeight);
            pnlWindowPos2v.Visible = false;
        }

        private void btnPos2v_2_Click(object sender, EventArgs e)
        {
            int posYini = 0;
            int posXini = (Screen.PrimaryScreen.WorkingArea.Width / 2) + 1;
            int windowHeight = Screen.PrimaryScreen.WorkingArea.Height;
            int windowWidth = (Screen.PrimaryScreen.WorkingArea.Width / 2) - 1;
            SetWindow(posXini, posYini, windowWidth, windowHeight);
            pnlWindowPos2v.Visible = false;
        }

        private void btnPos2v_Cancel_Click(object sender, EventArgs e)
        {
            pnlWindowPos2v.Visible = false;
        }
        #endregion

        #region Remote command to arrange

        private void PostRemoteCommandWindowMessage(int wmMsg, int limit)
        {
            PostRemoteCommandWindowMessage(wmMsg, limit, false);
        }

        private void PostRemoteCommandWindowMessage(int wmMsg, int limit, bool butThis)
        {
            int cont = 1;
            int wmMsgZero = wmMsg;
            int myProcessId = Process.GetCurrentProcess().Id;
            string myProcessName = Process.GetCurrentProcess().ProcessName; // por causa dessa linha não funciona em modo debug
            Process[] processes = Process.GetProcessesByName(myProcessName);

            foreach (Process p in processes)
            {
                if (butThis)
                {
                    if (p.Id != myProcessId)
                    {
                        int hwnd = (int)p.MainWindowHandle;
                        SendMessage(hwnd, wmMsg, 0, 0);

                        wmMsg++;
                        cont++;

                        if (wmMsg >= (wmMsgZero + limit))
                        {
                            wmMsg = wmMsgZero;
                            cont++;
                        }
                    }
                }
                else
                {
                    int hwnd = (int)p.MainWindowHandle;
                    SendMessage(hwnd, wmMsg, 0, 0);

                    wmMsg++;
                    cont++;

                    if (wmMsg >= (wmMsgZero + limit))
                    {
                        wmMsg = wmMsgZero;
                        cont++;
                    }
                }

                Thread.Sleep(1);
            }
        }


        protected override void WndProc(ref Message m)
        {
            // Check if it is a message we want to handle
            // based upon it's message type
            switch (m.Msg)
            {
                case WM_SPLIT2H1:
                    btnPos2h_1_Click(null, null);
                    break;
                case WM_SPLIT2H2:
                    btnPos2h_2_Click(null, null);
                    break;
                case WM_SPLIT2V1:
                    btnPos2v_1_Click(null, null);
                    break;
                case WM_SPLIT2V2:
                    btnPos2v_2_Click(null, null);
                    break;
                case WM_SPLIT3H1:
                    btnPos3h_1_Click(null, null);
                    break;
                case WM_SPLIT3H2:
                    btnPos3h_2_Click(null, null);
                    break;
                case WM_SPLIT3H3:
                    btnPos3h_3_Click(null, null);
                    break;
                case WM_SPLIT3V1:
                    btnPos3v_1_Click(null, null);
                    break;
                case WM_SPLIT3V2:
                    btnPos3v_2_Click(null, null);
                    break;
                case WM_SPLIT3V3:
                    btnPos3v_3_Click(null, null);
                    break;
                case WM_SPLIT4_1:
                    btnPos4_1_Click(null, null);
                    break;
                case WM_SPLIT4_2:
                    btnPos4_2_Click(null, null);
                    break;
                case WM_SPLIT4_3:
                    btnPos4_3_Click(null, null);
                    break;
                case WM_SPLIT4_4:
                    btnPos4_4_Click(null, null);
                    break;
                case WM_SPLIT6_1:
                    btnPos6_1_Click(null, null);
                    break;
                case WM_SPLIT6_2:
                    btnPos6_2_Click(null, null);
                    break;
                case WM_SPLIT6_3:
                    btnPos6_3_Click(null, null);
                    break;
                case WM_SPLIT6_4:
                    btnPos6_4_Click(null, null);
                    break;
                case WM_SPLIT6_5:
                    btnPos6_5_Click(null, null);
                    break;
                case WM_SPLIT6_6:
                    btnPos6_6_Click(null, null);
                    break;
                default: //Se não for comando particular...
                    base.WndProc(ref m);
                    break;
            }
        }

        #endregion

        private void centralizeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            int posYini = (Screen.PrimaryScreen.WorkingArea.Height / 2) - (this.Height / 2);
            int posXini = (Screen.PrimaryScreen.WorkingArea.Width / 2) - (this.Width / 2); ;
            int windowHeight = this.Height;
            int windowWidth = this.Width;
            SetWindow(posXini, posYini, windowWidth, windowHeight);
        }

        private void SetWindow(int posX, int posY, int width, int height)
        {
            this.StartPosition = FormStartPosition.Manual;
            Point p = new Point(posX, posY);
            this.Location = p;
            Size s = new Size(width, height);
            this.Size = s;
            this.Update();
        }

        #endregion

        #region Drag and Drop

        private void txtContent_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.Copy;
            else
                e.Effect = DragDropEffects.None;
        }

        private void txtContent_DragDrop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] filesArgument = (string[])e.Data.GetData(DataFormats.FileDrop);

                Thread thr = new Thread(new ParameterizedThreadStart(TrataDragAndDrop));
                thr.Start(filesArgument);
            }
        }

        private void TrataDragAndDrop(object argument)
        {
            string[] filesArgument = (string[])argument;
            string mySelfExecutableFile;
            string myArgumentFile = string.Empty;

            if (filesArgument != null)
            {
                mySelfExecutableFile = Application.ExecutablePath;

                if (filesArgument.Length > 0)
                {
                    if (filesArgument.Length > 1)
                    {
                        string argsToNextProcess = string.Empty;

                        for (int idx = 1; idx < filesArgument.Length; idx++)
                        {
                            argsToNextProcess += filesArgument[idx].Replace(" ", "*") + " ";
                        }

                        Thread.Sleep(500);
                        Process.Start(mySelfExecutableFile, argsToNextProcess.Substring(0, argsToNextProcess.Length - 1));
                    }
                    myArgumentFile = filesArgument[0];

                    CloseFile();
                    OpenFile(myArgumentFile);
                }
            }//
        }

        #endregion
        private void VisibleLinesCalc()
        {
            _visibleLines = (txtContent.Height / 16);
            if (_fileVirtualization != null)
            {
                _fileVirtualization.SetLinesToVirtualize(_visibleLines);
            }

        }



    }
}
